<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import ChatHeader from '@/components/ChatHeader.vue'
import ChatSidebar from '@/components/ChatSidebar.vue'
import ChatMessages from '@/components/ChatMessages.vue'
import ChatInput from '@/components/ChatInput.vue'
import { getSessions, getMessages, createSession, deleteSession as apiDeleteSession, sendChat, difyUpload, difyRun, connectSSE, sendStreamChat } from '@/api/chatApi.js'

const userId = ref(1)
const chatSessions = ref([])
const selectedSessionId = ref(null)
const messages = ref([])
const prompt = ref('')
const lastRunId = ref('')
// 仅预览：已上传待处理的文件
const selectedFileId = ref('')
const selectedFileName = ref('')
const lastSentFileName = ref('')
// 流式聊天相关状态
const sseConnected = ref(false)
const isStreaming = ref(false)
const streamingMessageId = ref(null)

function goBack() { history.back() }

async function loadChatSessions() { chatSessions.value = await getSessions(userId.value) }
// 文件名本地持久化：messageId -> fileName
function getFileHints() {
  try { return JSON.parse(localStorage.getItem('fileHints') || '{}') } catch { return {} }
}
function setFileHint(messageId, name) {
  const hints = getFileHints()
  hints[String(messageId)] = name
  localStorage.setItem('fileHints', JSON.stringify(hints))
}
function applyFileHints(list) {
  const hints = getFileHints()
  if (!list || !Array.isArray(list)) return list
  return list.map(m => {
    const hint = hints && m && m.messageId != null ? hints[String(m.messageId)] : undefined
    return hint ? { ...m, fileName: hint } : m
  })
}

async function loadSessionMessages(id) {
  const list = await getMessages(id)
  messages.value = applyFileHints(list)
}

async function selectSession(session) {
  selectedSessionId.value = session.sessionId
  await loadSessionMessages(session.sessionId)
}

async function createNewSession() {
  const data = await createSession(userId.value, '新会话')
  selectedSessionId.value = data.sessionId
  await loadChatSessions()
}

async function deleteSession(id) {
  await apiDeleteSession(id)
  if (selectedSessionId.value === id) {
    selectedSessionId.value = null
    messages.value = []
  }
  await loadChatSessions()
}

async function sendMessage() {
  const content = prompt.value.trim()
  if (!content) return
  if (!selectedSessionId.value) {
    await createNewSession()
  }
  try {
    if (selectedFileId.value) {
      const currentFileName = selectedFileName.value
      const runPayload = {
        inputs: {
          input: { type: 'document', transfer_method: 'local_file', upload_file_id: selectedFileId.value },
          sessionId: selectedSessionId.value,
          userId: userId.value
        },
        response_mode: 'blocking',
        query: content
      }
      const runRes = await difyRun(runPayload)
      lastRunId.value = runRes?.workflow_run_id || runRes?.id || ''
      prompt.value = ''
      // 发送后，将文件名绑定到"最新一条用户消息"上
      lastSentFileName.value = currentFileName || ''
      // 清除输入框上的文件预览
      clearSelectedFile()
      const sid = selectedSessionId.value
      await loadSessionMessages(sid)
      if (lastSentFileName.value) {
        const arr = Array.isArray(messages.value) ? messages.value.slice() : []
        for (let i = arr.length - 1; i >= 0; i--) {
          const m = arr[i]
          if (m && m.role === 'user') {
            const withName = { ...m, fileName: lastSentFileName.value }
            arr[i] = withName
            if (withName.messageId != null) setFileHint(withName.messageId, lastSentFileName.value)
            break
          }
        }
        messages.value = arr
        lastSentFileName.value = ''
      }
      await loadChatSessions()
    } else {
      // 使用流式聊天
      await sendStreamMessage()
    }
  } finally { }
}

async function onPlusClick() {
  const input = document.createElement('input')
  input.type = 'file'
  input.onchange = async () => {
    const file = input.files && input.files[0]
    if (!file) return
    const uploadRes = await difyUpload(file, String(userId.value), { sessionId: selectedSessionId.value, userId: userId.value })
    const fileId = uploadRes?.id || uploadRes?.data?.id || uploadRes?.file_id
    if (!fileId) { alert('文件上传失败，请重试'); return }
    selectedFileId.value = fileId
    selectedFileName.value = file.name
  }
  input.click()
}

function clearSelectedFile() {
  selectedFileId.value = ''
  selectedFileName.value = ''
}

// 初始化SSE连接
function initSSEConnection() {
  const eventSource = connectSSE(userId.value)
  
  // 监听流式添加消息事件
  eventSource.addEventListener('add', (event) => {
    if (isStreaming.value && streamingMessageId.value !== null) {
      const msgList = messages.value
      const index = msgList.findIndex(m => m.messageId === streamingMessageId.value)
      if (index >= 0) {
        msgList[index].content += event.data
        messages.value = [...msgList]
      }
    }
  })
  
  // 监听消息完成事件
  eventSource.addEventListener('finish', () => {
    if (isStreaming.value) {
      const msgList = messages.value
      const index = msgList.findIndex(m => m.messageId === streamingMessageId.value)
      if (index >= 0) {
        msgList[index].streaming = false
        messages.value = [...msgList]
      }
      
      isStreaming.value = false
      streamingMessageId.value = null
      
      // 刷新会话列表，获取最新状态
      loadChatSessions()
    }
  })
  
  eventSource.onerror = () => {
    sseConnected.value = false
    isStreaming.value = false
    // 尝试重连
    setTimeout(initSSEConnection, 3000)
  }
  
  eventSource.onopen = () => {
    sseConnected.value = true
  }
}

// 发送流式聊天消息
async function sendStreamMessage() {
  const content = prompt.value.trim()
  if (!content || isStreaming.value) return
  
  if (!selectedSessionId.value) {
    await createNewSession()
  }
  
  try {
    // 创建一个"等待中"的消息
    const userMessage = {
      messageId: Date.now(),
      role: 'user',
      content: content,
      createTime: new Date().toISOString()
    }
    
    const assistantMessage = {
      messageId: Date.now() + 1,
      role: 'assistant',
      content: '',
      streaming: true, // 表示正在流式接收中
      createTime: new Date().toISOString()
    }
    
    messages.value = [...messages.value, userMessage, assistantMessage]
    streamingMessageId.value = assistantMessage.messageId
    isStreaming.value = true
    
    prompt.value = ''
    
    // 发送流式聊天请求
    await sendStreamChat(userId.value, content, selectedSessionId.value)
  } catch (error) {
    console.error('发送流式消息出错:', error)
    isStreaming.value = false
    streamingMessageId.value = null
  }
}

onMounted(async () => {
  localStorage.setItem('userId', String(userId.value))
  await loadChatSessions()
  initSSEConnection()
})

onUnmounted(() => {
  // 关闭SSE连接
  if (window.eventSource) {
    window.eventSource.close()
  }
})
</script>

<template>
  <div class="ai-chat">
    <ChatHeader @back="goBack" />

    <div class="chat-container">
      <ChatSidebar :sessions="chatSessions" :selected-id="selectedSessionId" @create="createNewSession"
        @select="selectSession" @delete="deleteSession" />

      <div class="main-chat-area">
        <ChatMessages :messages="messages" />

        <div v-if="selectedFileName" class="file-preview">
          <span class="file-name">{{ selectedFileName }}</span>
          <button class="file-clear" @click="clearSelectedFile" title="取消">×</button>
        </div>

        <ChatInput v-model="prompt" :disabled="!selectedSessionId" @send="sendMessage" @plus="onPlusClick" />
      </div>
    </div>
  </div>
</template>

<style scoped>
/* 头部 */
.ai-chat {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background: #f5f5f5;
  color: #121212;
}

.chat-header {
  border-bottom: 1px solid #e0e0e0;
  padding: 10px 16px;
}

.header-content {
  display: flex;
  align-items: center;
  gap: 12px;
}

.back-button {
  background: transparent;
  border: 1px solid #d0d0d0;
  color: #333333;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  cursor: pointer;
}

.back-button:hover {
  background: #e9e9e9;
}

.title-section {
  flex: 1;
}

.chat-title {
  font-size: 16px;
  margin: 0;
}

/* 布局 */
.chat-container {
  display: grid;
  grid-template-columns: 280px 1fr;
  flex: 1;
  min-height: 0;
}

.chat-sidebar {
  border-right: 1px solid #e0e0e0;
  padding: 12px;
  overflow: auto;
}

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

.sidebar-header h3 {
  margin: 0;
  font-size: 14px;
  color: #000;
}

.new-chat-btn {
  background: #000;
  color: #fff;
  border: none;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  cursor: pointer;
  display: grid;
  place-items: center;
}

.history-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.no-history {
  color: #777;
  font-size: 13px;
}

.history-item {
  background: #ffffff;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  padding: 10px;
  cursor: pointer;
}

.history-item.active {
  border-color: #bbbbbb;
  background: #f0f0f0;
}

.history-content {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: center;
}

.history-question {
  color: #121212;
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.session-info {
  color: #777;
  font-size: 12px;
}

.floating-delete-btn {
  background: transparent;
  border: 1px solid #d0d0d0;
  color: #555;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  cursor: pointer;
}

.floating-delete-btn:disabled {
  opacity: .5;
  cursor: not-allowed;
}

/* 主聊天区 */
.main-chat-area {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.messages-container {
  flex: 1;
  overflow: auto;
  padding: 16px;
}

.welcome-message {
  display: grid;
  place-items: center;
  height: 100%;
  color: #555;
}

.welcome-content h2 {
  margin: 0 0 6px;
}

.chat-message {
  display: flex;
  gap: 10px;
  margin-bottom: 12px;
}

.user-message {
  flex-direction: row-reverse;
}

.message-avatar {
  width: 40px;
  display: grid;
  place-items: center;
}

.avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 12px;
}

.user-avatar {
  background: #333;
  color: #fff;
}

.ai-avatar {
  background: #f0f0f0;
  color: #000;
  border: 1px solid #d0d0d0;
}

.message-content {
  max-width: 70%;
}

.message-bubble {
  background: #f0f0f0;
  border: 1px solid #e1e1e1;
  border-radius: 10px;
  padding: 10px 12px;
  color: #121212;
}

.user-message .message-bubble {
  background: #222222;
  color: #fff;
  border-color: #333333;
}

/* 输入框 */
.chat-input {
  display: flex;
  gap: 8px;
  padding: 12px;
  border-top: 1px solid #e0e0e0;
}

.prompt-input {
  flex: 1;
  background: #ffffff;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  color: #121212;
  padding: 10px 12px;
  outline: none;
}

.prompt-input::placeholder {
  color: #999;
}

.send-btn {
  background: #000;
  color: #fff;
  border: none;
  padding: 10px 16px;
  border-radius: 8px;
  cursor: pointer;
}

.send-btn:disabled {
  opacity: .6;
  cursor: not-allowed;
}

/* 文件预览条 */
.file-preview { display: flex; align-items: center; gap: 8px; padding: 6px 12px; margin: 0 16px 8px; background: #ffffff; border: 1px solid #e0e0e0; border-radius: 8px; width: fit-content; }
.file-name { font-size: 13px; color: #333; }
.file-clear { background: transparent; border: none; cursor: pointer; font-size: 16px; line-height: 16px; color: #666; }

/* 打字动画 */
.typing-dots {
  display: inline-flex;
  gap: 4px;
  align-items: center;
}

.typing-dots span {
  width: 6px;
  height: 6px;
  background: #eaeaea;
  border-radius: 50%;
  display: inline-block;
  animation: blink 1.2s infinite ease-in-out;
}

.typing-dots span:nth-child(2) {
  animation-delay: .2s;
}

.typing-dots span:nth-child(3) {
  animation-delay: .4s;
}

@keyframes blink {

  0%,
  80%,
  100% {
    opacity: .2
  }

  40% {
    opacity: 1
  }
}
</style>
